// thread.cpp
// Copyright (C) 2008 Sam Bateman
// samuel.bateman@gmail.com
//
// This file is part of DVD On Fire.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//! @file thread.cpp
//! @author Sam Bateman
//! @brief Source file for the Thread class.

#include <pthread.h>
#include "thread.h"

namespace dvdonfire
{
    namespace lib
    {
        // runThread(arg) {{{
        void* runThread(void *arg)
        {
            Runnable *runner = (Runnable *)arg;
            runner->run();
            return NULL;
        }
        // }}}
        // struct Thread::Impl {{{
        struct Thread::Impl
        {
            bool       interrupted;
            Runnable  *runner;
            pthread_t  tid;
        };
        // }}}
        // Thread::Thread(r) {{{
        //! @brief Constructor.
        //! @param r Object to run.
        Thread::Thread(Runnable *r)
        {
            impl = new Impl;
            impl->interrupted = false;
            impl->runner = r;
            impl->tid = 0;
        }
        // }}}
        // Thread::~Thread() {{{
        //! @brief Destructor.
        Thread::~Thread()
        {
            if (impl->tid != 0) stop();
            delete impl;
        }
        // }}}
        // Thread::start() {{{
        //! @brief Starts executing the thread.
        //!
        //! Creates and runs a separate thread of execution, using the run()
        //! method of the Runnable object passed to the constructor.  Until
        //! this function is called, no new thread is created.
        void Thread::start()
        {
            pthread_create(&impl->tid, NULL, runThread, impl->runner);
        }
        // }}}
        // Thread::stop() {{{
        //! @brief Stops executing the thread.
        //!
        //! Interrupts the currently-running thread.  This function will not
        //! return until the thread is stopped (i.e. the Runnable's run()
        //! method has returned).
        void Thread::stop()
        {
            impl->interrupted = true;
            pthread_join(impl->tid, NULL);
            impl->tid = 0;
        }
        // }}}
        // Thread::yield() {{{
        //! @brief Yields the processor.
        //! @return Whether stop() has been called.
        //!
        //! Yields the processor to other processes/threads that need it.  The
        //! Runnable's run() method should call this to avoid being a CPU hog.
        //! If this method returns true, the run() method should exit.
        bool Thread::yield()
        {
            sched_yield();
            return impl->interrupted;
        }
        // }}}
    }
}
